This post includes notes that I took from watching a presentation given by Eduardo Ariño de la, the Chief Data Scientist at Domino Data Lab. In his presentation, he introduces 23 visualizations and the appropriate scenarios to use them. You can find the presentation here, Video- 23 Visualizations and when to use them. My goal is to familiarize myself with these plots by writing the code using mainly ggplot and datasets that I am familiar with.

Load Libraries

library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ---------------------------------------------------------------------------------------------------
filter(): dplyr, stats
lag():    dplyr, stats
library(lubridate)

Attaching package: ‘lubridate’

The following object is masked from ‘package:base’:

    date
library(readxl)
theme_set(theme_classic())
options(scipen=999)

Loading Global Superstore Dataset

global = read_excel("global_superstore.xls", sheet = 1, col_names = T)
DEFINEDNAME: 21 00 00 01 0b 00 00 00 01 00 00 00 00 00 00 0d 3b 02 00 00 00 5a c8 00 00 17 00 
DEFINEDNAME: 8b 03 00 0f 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 44 49 53 54 1c 1d 
DEFINEDNAME: 8b 03 00 0e 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 49 4e 56 1c 1d 
DEFINEDNAME: 00 00 00 0b 07 00 00 00 00 00 00 00 00 00 00 4c 61 6e 67 75 61 67 65 5f 49 44 3a 01 00 00 00 04 00 
DEFINEDNAME: 21 00 00 01 0b 00 00 00 01 00 00 00 00 00 00 0d 3b 02 00 00 00 5a c8 00 00 17 00 
DEFINEDNAME: 8b 03 00 0f 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 44 49 53 54 1c 1d 
DEFINEDNAME: 8b 03 00 0e 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 49 4e 56 1c 1d 
DEFINEDNAME: 00 00 00 0b 07 00 00 00 00 00 00 00 00 00 00 4c 61 6e 67 75 61 67 65 5f 49 44 3a 01 00 00 00 04 00 
DEFINEDNAME: 21 00 00 01 0b 00 00 00 01 00 00 00 00 00 00 0d 3b 02 00 00 00 5a c8 00 00 17 00 
DEFINEDNAME: 8b 03 00 0f 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 44 49 53 54 1c 1d 
DEFINEDNAME: 8b 03 00 0e 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 49 4e 56 1c 1d 
DEFINEDNAME: 00 00 00 0b 07 00 00 00 00 00 00 00 00 00 00 4c 61 6e 67 75 61 67 65 5f 49 44 3a 01 00 00 00 04 00 
DEFINEDNAME: 21 00 00 01 0b 00 00 00 01 00 00 00 00 00 00 0d 3b 02 00 00 00 5a c8 00 00 17 00 
DEFINEDNAME: 8b 03 00 0f 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 44 49 53 54 1c 1d 
DEFINEDNAME: 8b 03 00 0e 02 00 00 00 00 00 00 00 00 00 00 5f 78 6c 66 6e 2e 4e 4f 52 4d 2e 49 4e 56 1c 1d 
DEFINEDNAME: 00 00 00 0b 07 00 00 00 00 00 00 00 00 00 00 4c 61 6e 67 75 61 67 65 5f 49 44 3a 01 00 00 00 04 00 
Expecting numeric in [898, 12] got `05408`Expecting numeric in [1184, 12] got `05408`Expecting numeric in [3115, 12] got `05408`Expecting numeric in [4790, 12] got `05408`Expecting numeric in [6399, 12] got `05408`Expecting numeric in [23425, 12] got `05408`Expecting numeric in [26001, 12] got `05408`Expecting numeric in [43152, 12] got `05408`Expecting numeric in [45778, 12] got `05408`Expecting numeric in [50150, 12] got `05408`Expecting numeric in [50413, 12] got `05408`

Data Munging

# rename variables
global = rename(global, row_id = `Row ID`, order_id = `Order ID`, order_date = `Order Date`, ship_date = `Ship Date`, ship_mode = `Ship Mode`, customer_id = `Customer ID`, customer_name = `Customer Name`, segment = Segment, city = City, state = State, country = Country, postal_code = `Postal Code`, market = Market, region = Region, product_id = `Product ID`, category = Category, sub_category = `Sub-Category`, product_name = `Product Name`, sales = Sales, quantity = Quantity, discount = `Discount`, profit = `Profit`, shipping_cost = `Shipping Cost`, order_priority = `Order Priority`)

Adding new date columns based on weekday, day, month and year.

global = global %>% 
  mutate(weekday = wday(order_date, label = T),
        day = day(order_date),
        month = month(order_date, label = T),
        year = year(order_date))
global

Deviation

Deviation can be used to emphasize variation from a fixed reference point such as 0, average or any target.

diverging_profit =
global %>%
  mutate(gain_loss = ifelse(profit < 0, 'loss', 'gain')) %>%
  select(order_date, region, profit, gain_loss) %>%
  arrange(profit)
  ggplot(diverging_profit, aes(x = region, y = profit, label = profit)) +
  geom_bar(stat='identity', aes(fill=gain_loss), width=.8) + 
  labs(title = "Diverging Bar", subtitle = "Profit loss or gain from a fixed reference point of 0")+
  coord_flip()+
  scale_fill_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

ggplot(diverging_profit, aes(x=region, y=profit, label=profit)) + 
  geom_point(stat='identity', aes(colour=gain_loss), size=2, alpha = 0.6) +  
  labs(title = "Diverging Dot Plot", 
       subtitle = "Profit loss or gain from a fixed reference point of 0") + 
  coord_flip() + scale_colour_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

filter_2012 = global %>% 
  mutate(gain_loss = ifelse(profit > 0, 'gain', 'loss')) %>%
  filter(order_date < "2011-06-01")
  
ggplot(filter_2012, aes(order_date, profit, fill = gain_loss )) +
  geom_area() + labs(title = "Diverging Area Chart", subtitle = "Profit loss or gain from a fixed reference point of 0") + scale_fill_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

Correlation

Correlation shows the relationship between two or more variables.

ggplot(global, aes(x = sales, y = profit)) + 
  geom_point(aes(col = segment), alpha = 0.6) +
  geom_smooth(method = "loess", se = F) + 
  labs(title = "Scatterplot with Smoothing Line Based on LOESS", subtitle = "Sales vs Profit") +
  scale_colour_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

Ranking

Ranking is useful where ordered list is important.

ranked_region = 
  global %>% 
  select(region, sales)%>%
  group_by(region) %>%
  summarise(sum = sum(sales)) %>%
  mutate(region = factor(region, levels = region[order(sum, decreasing = TRUE)]))
  
ggplot(ranked_region, aes(x = region, y = sum)) +
  geom_bar(stat = "identity", width = .8, fill = "#1F77B4")+ 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
  labs(title = "Ranked Bar Chart", subtitle = "Sales by Region") 

NA
ggplot(ranked_region, aes(x = region, y = sum)) +
  geom_point(size = 3, col = "#1F77B4", alpha = 0.9)+
  geom_segment(aes(x = region, 
               xend = region,
               y = min(sum),
               yend = max(sum)),
              linetype = "dashed",
              size = 0.1) + 
  labs(title = "Dot Plot Ranking Bar", subtitle = "Sales vs Region") +
  coord_flip()

Distribution

Distribution plots show how often values of a variable occur.

ggplot(mpg, aes(x = hwy)) + 
  geom_histogram(bins = 7,col = "black", fill = "#1F77B4") +
  labs(title = "Histogram", subtitle = "Count of Highway Miles") 

Data munging

mtcars$cyl = as.factor(mtcars$cyl)
mtcars
ggplot(mtcars, aes(wt)) + 
  geom_density(aes(fill = factor(cyl)), alpha = 0.7) + xlim(0,6)+
  labs(title="Density plot", 
         subtitle="Weight (1000 lbs) per Cylinder",
         caption="Source: mtcars",
         x="Weight",
         fill="Cylinders") + 
  scale_fill_manual(values = c("#1F77B4", "#2CA02C","#FF7F0E"))

ggplot(mtcars, aes(cyl, qsec, group = cyl)) +
  geom_boxplot(varwidth = T, fill = "#1F77B4") +
  labs(title="Boxplot", 
         subtitle="1/4 mile time per Cylinder",
         caption="Source: mtcars",
         x="Cylinders")

Composition

Compositions graphs show how a single entity can be broken down into its components elements.

ggplot(global, aes(sub_category)) +
  geom_bar(aes(fill = category)) +
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
   labs(title="Composition", 
         subtitle="Counts of Sub-Category - Grouped by Category",
         caption="Source: Superstore",
         x="Sub-Category",
         fill = "Category" ) +
  scale_fill_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

NA
global

Stacked Column

ggplot(global, aes(market)) +
  geom_bar(aes(fill = category)) + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
  labs(title="Category Stacked - Bar Chart", 
       subtitle="Markets - Grouped by Category", 
       x = "Market",
       fill = "Category",
       caption="Source: Superstore") +
  scale_fill_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

global_treemap = global %>%
  filter(year == 2012, month == 'Jan') %>%
  mutate(country = as.factor(country),
          region = as.factor(region),
         market = as.factor(market))
library(treemapify)
Loading required package: plyr
------------------------------------------------------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
------------------------------------------------------------------------------------------------------------------------------

Attaching package: ‘plyr’

The following object is masked from ‘package:lubridate’:

    here

The following objects are masked from ‘package:dplyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following object is masked from ‘package:purrr’:

    compact

Loading required package: reshape2

Attaching package: ‘reshape2’

The following object is masked from ‘package:tidyr’:

    smiths

Package treemapify 0.2.2 has been loaded!
treeMapCoordinates <- treemapify(
  global_treemap,
  area = "sales",
  fill = "profit",
  group = "market")
treeMapPlot <- ggplotify(treeMapCoordinates)
print(treeMapPlot)

Change

Change gives emphasis to changing trends.

year_2012 = 
  global %>% 
  filter(year == 2012)
  ggplot(year_2012, aes(order_date, sales)) + 
    geom_line(col = "#1F77B4") + 
    facet_wrap(~segment, nrow = 3) +
    labs(title="Change Trends", 
       subtitle="Sales by segment", 
       x = "Date",
       caption="Source: Superstore")

Heatmap - with heatmaps we can spot variations of a metric.

mtcars_matrix =  data.matrix(mtcars)
library(superheat)
superheat(mtcars_matrix,
          left.label.size = 0.3,
          left.label.text.size = 3,
          legend.text.size = 12,
          padding = .1)


Video - 23 Visualizations and when to use them

LS0tCnRpdGxlOiAnVmlzdWFsaXphdGlvbjogV2hlbiB0byB1c2UgdGhlbSEnCmF1dGhvcjogQmVybmFyZCBBZGUKZGF0ZTogMi0wOC0yMDE3Cm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKVGhpcyBwb3N0IGluY2x1ZGVzIG5vdGVzIHRoYXQgSSB0b29rIGZyb20gd2F0Y2hpbmcgYSBwcmVzZW50YXRpb24gZ2l2ZW4gYnkgRWR1YXJkbyBBcmnDsW8gZGUgbGEsIHRoZSBDaGllZiBEYXRhIFNjaWVudGlzdCBhdCBEb21pbm8gRGF0YSBMYWIuICBJbiBoaXMgcHJlc2VudGF0aW9uLCBoZSBpbnRyb2R1Y2VzIDIzIHZpc3VhbGl6YXRpb25zIGFuZCB0aGUgYXBwcm9wcmlhdGUgc2NlbmFyaW9zIHRvIHVzZSB0aGVtLgpZb3UgY2FuIGZpbmQgdGhlIHByZXNlbnRhdGlvbiBoZXJlLCBbVmlkZW8tIDIzIFZpc3VhbGl6YXRpb25zIGFuZCB3aGVuIHRvIHVzZSB0aGVtXShodHRwczovL2Jsb2cuZG9taW5vZGF0YWxhYi5jb20vdmlkZW8tMjMtdmlzdWFsaXphdGlvbnMtdXNlLykuIE15IGdvYWwgaXMgdG8gZmFtaWxpYXJpemUgbXlzZWxmIHdpdGggdGhlc2UgcGxvdHMgYnkgd3JpdGluZyB0aGUgY29kZSB1c2luZyBtYWlubHkgZ2dwbG90IGFuZCBkYXRhc2V0cyB0aGF0IEkgYW0gZmFtaWxpYXIgd2l0aC4KCiMjI0xvYWQgTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkocmVhZHhsKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpvcHRpb25zKHNjaXBlbj05OTkpCmBgYAojIyMjTG9hZGluZyBHbG9iYWwgU3VwZXJzdG9yZSBEYXRhc2V0CmBgYHtyfQpnbG9iYWwgPSByZWFkX2V4Y2VsKCJnbG9iYWxfc3VwZXJzdG9yZS54bHMiLCBzaGVldCA9IDEsIGNvbF9uYW1lcyA9IFQpCmBgYAoKIyMjI0RhdGEgTXVuZ2luZwpgYGB7cn0KIyByZW5hbWUgdmFyaWFibGVzCmdsb2JhbCA9IHJlbmFtZShnbG9iYWwsIHJvd19pZCA9IGBSb3cgSURgLCBvcmRlcl9pZCA9IGBPcmRlciBJRGAsIG9yZGVyX2RhdGUgPSBgT3JkZXIgRGF0ZWAsIHNoaXBfZGF0ZSA9IGBTaGlwIERhdGVgLCBzaGlwX21vZGUgPSBgU2hpcCBNb2RlYCwgY3VzdG9tZXJfaWQgPSBgQ3VzdG9tZXIgSURgLCBjdXN0b21lcl9uYW1lID0gYEN1c3RvbWVyIE5hbWVgLCBzZWdtZW50ID0gU2VnbWVudCwgY2l0eSA9IENpdHksIHN0YXRlID0gU3RhdGUsIGNvdW50cnkgPSBDb3VudHJ5LCBwb3N0YWxfY29kZSA9IGBQb3N0YWwgQ29kZWAsIG1hcmtldCA9IE1hcmtldCwgcmVnaW9uID0gUmVnaW9uLCBwcm9kdWN0X2lkID0gYFByb2R1Y3QgSURgLCBjYXRlZ29yeSA9IENhdGVnb3J5LCBzdWJfY2F0ZWdvcnkgPSBgU3ViLUNhdGVnb3J5YCwgcHJvZHVjdF9uYW1lID0gYFByb2R1Y3QgTmFtZWAsIHNhbGVzID0gU2FsZXMsIHF1YW50aXR5ID0gUXVhbnRpdHksIGRpc2NvdW50ID0gYERpc2NvdW50YCwgcHJvZml0ID0gYFByb2ZpdGAsIHNoaXBwaW5nX2Nvc3QgPSBgU2hpcHBpbmcgQ29zdGAsIG9yZGVyX3ByaW9yaXR5ID0gYE9yZGVyIFByaW9yaXR5YCkKYGBgCiMjIyMgQWRkaW5nIG5ldyBkYXRlIGNvbHVtbnMgYmFzZWQgb24gd2Vla2RheSwgZGF5LCBtb250aCBhbmQgeWVhci4KYGBge3J9Cmdsb2JhbCA9IGdsb2JhbCAlPiUgCiAgbXV0YXRlKHdlZWtkYXkgPSB3ZGF5KG9yZGVyX2RhdGUsIGxhYmVsID0gVCksCiAgICAgICAgZGF5ID0gZGF5KG9yZGVyX2RhdGUpLAogICAgICAgIG1vbnRoID0gbW9udGgob3JkZXJfZGF0ZSwgbGFiZWwgPSBUKSwKICAgICAgICB5ZWFyID0geWVhcihvcmRlcl9kYXRlKSkKYGBgCgpgYGB7cn0KZ2xvYmFsCmBgYAoKCiMjI0RldmlhdGlvbiAKIyMjI0RldmlhdGlvbiBjYW4gYmUgdXNlZCB0byBlbXBoYXNpemUgdmFyaWF0aW9uIGZyb20gYSBmaXhlZCByZWZlcmVuY2UgcG9pbnQgc3VjaCBhcyAwLCBhdmVyYWdlIG9yIGFueSB0YXJnZXQuIApgYGB7cn0KZGl2ZXJnaW5nX3Byb2ZpdCA9Cmdsb2JhbCAlPiUKICBtdXRhdGUoZ2Fpbl9sb3NzID0gaWZlbHNlKHByb2ZpdCA8IDAsICdsb3NzJywgJ2dhaW4nKSkgJT4lCiAgc2VsZWN0KG9yZGVyX2RhdGUsIHJlZ2lvbiwgcHJvZml0LCBnYWluX2xvc3MpICU+JQogIGFycmFuZ2UocHJvZml0KQoKICBnZ3Bsb3QoZGl2ZXJnaW5nX3Byb2ZpdCwgYWVzKHggPSByZWdpb24sIHkgPSBwcm9maXQsIGxhYmVsID0gcHJvZml0KSkgKwogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgYWVzKGZpbGw9Z2Fpbl9sb3NzKSwgd2lkdGg9LjgpICsgCiAgbGFicyh0aXRsZSA9ICJEaXZlcmdpbmcgQmFyIiwgc3VidGl0bGUgPSAiUHJvZml0IGxvc3Mgb3IgZ2FpbiBmcm9tIGEgZml4ZWQgcmVmZXJlbmNlIHBvaW50IG9mIDAiKSsKICBjb29yZF9mbGlwKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ2FpbiI9IiMxRjc3QjQiLCAibG9zcyI9IiNGRjdGMEUiKSkKCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoZGl2ZXJnaW5nX3Byb2ZpdCwgYWVzKHg9cmVnaW9uLCB5PXByb2ZpdCwgbGFiZWw9cHJvZml0KSkgKyAKICBnZW9tX3BvaW50KHN0YXQ9J2lkZW50aXR5JywgYWVzKGNvbG91cj1nYWluX2xvc3MpLCBzaXplPTIsIGFscGhhID0gMC42KSArICAKICBsYWJzKHRpdGxlID0gIkRpdmVyZ2luZyBEb3QgUGxvdCIsIAogICAgICAgc3VidGl0bGUgPSAiUHJvZml0IGxvc3Mgb3IgZ2FpbiBmcm9tIGEgZml4ZWQgcmVmZXJlbmNlIHBvaW50IG9mIDAiKSArIAogIGNvb3JkX2ZsaXAoKSArIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiZ2FpbiI9IiMxRjc3QjQiLCAibG9zcyI9IiNGRjdGMEUiKSkKCmBgYAoKCmBgYHtyfQpmaWx0ZXJfMjAxMiA9IGdsb2JhbCAlPiUgCiAgbXV0YXRlKGdhaW5fbG9zcyA9IGlmZWxzZShwcm9maXQgPiAwLCAnZ2FpbicsICdsb3NzJykpICU+JQogIGZpbHRlcihvcmRlcl9kYXRlIDwgIjIwMTEtMDYtMDEiKQogIApnZ3Bsb3QoZmlsdGVyXzIwMTIsIGFlcyhvcmRlcl9kYXRlLCBwcm9maXQsIGZpbGwgPSBnYWluX2xvc3MgKSkgKwogIGdlb21fYXJlYSgpICsgbGFicyh0aXRsZSA9ICJEaXZlcmdpbmcgQXJlYSBDaGFydCIsIHN1YnRpdGxlID0gIlByb2ZpdCBsb3NzIG9yIGdhaW4gZnJvbSBhIGZpeGVkIHJlZmVyZW5jZSBwb2ludCBvZiAwIikgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJnYWluIj0iIzFGNzdCNCIsICJsb3NzIj0iI0ZGN0YwRSIpKQpgYGAKCgojIyNDb3JyZWxhdGlvbgojIyMjQ29ycmVsYXRpb24gc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBvciBtb3JlIHZhcmlhYmxlcy4KYGBge3J9CmdncGxvdChnbG9iYWwsIGFlcyh4ID0gc2FsZXMsIHkgPSBwcm9maXQpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbCA9IHNlZ21lbnQpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRikgKyAKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXJwbG90IHdpdGggU21vb3RoaW5nIExpbmUgQmFzZWQgb24gTE9FU1MiLCBzdWJ0aXRsZSA9ICJTYWxlcyB2cyBQcm9maXQiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjMUY3N0I0IiwiI0ZGN0YwRSIsICIjMkNBMDJDIikpCgpgYGAKCgojIyMjIExvYWRpbmcgZnVlbCBlY29ub215IGRhdGEgZnJvbSAxOTk5IGFuZCAyMDA4IGZvciAzOCBwb3B1bGFyIG1vZGVscyBvZiBjYXIKYGBge3J9Cm1wZwpgYGAKCgpgYGB7cn0KIGdncGxvdChtcGcsIGFlcyh4ID0gaHd5LCB5ID0gZGlzcGwpKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiI0ZGN0YwRSIpKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEYpICsgCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVycGxvdCB3aXRoIFNtb290aGluZyBMaW5lIEJhc2VkIG9uIExPRVNTIiwgc3VidGl0bGUgPSAiRW5naW5lIERpc3BsYWNlbWVudCB2cyBIaWdod2F5IE1pbGVzIFBlciBHYWxsb24iKQpgYGAKCgojIyMgUmFua2luZwojIyMjUmFua2luZyBpcyB1c2VmdWwgd2hlcmUgb3JkZXJlZCBsaXN0IGlzIGltcG9ydGFudC4KYGBge3J9CnJhbmtlZF9yZWdpb24gPSAKICBnbG9iYWwgJT4lIAogIHNlbGVjdChyZWdpb24sIHNhbGVzKSU+JQogIGdyb3VwX2J5KHJlZ2lvbikgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShzYWxlcykpICU+JQogIG11dGF0ZShyZWdpb24gPSBmYWN0b3IocmVnaW9uLCBsZXZlbHMgPSByZWdpb25bb3JkZXIoc3VtLCBkZWNyZWFzaW5nID0gVFJVRSldKSkKICAKZ2dwbG90KHJhbmtlZF9yZWdpb24sIGFlcyh4ID0gcmVnaW9uLCB5ID0gc3VtKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IC44LCBmaWxsID0gIiMxRjc3QjQiKSsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIHZqdXN0PTAuNikpICsKICBsYWJzKHRpdGxlID0gIlJhbmtlZCBCYXIgQ2hhcnQiLCBzdWJ0aXRsZSA9ICJTYWxlcyBieSBSZWdpb24iKSAKICAKYGBgCgoKYGBge3J9CmdncGxvdChyYW5rZWRfcmVnaW9uLCBhZXMoeCA9IHJlZ2lvbiwgeSA9IHN1bSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2wgPSAiIzFGNzdCNCIsIGFscGhhID0gMC45KSsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSByZWdpb24sIAogICAgICAgICAgICAgICB4ZW5kID0gcmVnaW9uLAogICAgICAgICAgICAgICB5ID0gbWluKHN1bSksCiAgICAgICAgICAgICAgIHllbmQgPSBtYXgoc3VtKSksCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICBzaXplID0gMC4xKSArIAogIGxhYnModGl0bGUgPSAiRG90IFBsb3QgUmFua2luZyBCYXIiLCBzdWJ0aXRsZSA9ICJTYWxlcyB2cyBSZWdpb24iKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjRGlzdHJpYnV0aW9uCkRpc3RyaWJ1dGlvbiBwbG90cyBzaG93IGhvdyBvZnRlbiB2YWx1ZXMgb2YgYSB2YXJpYWJsZSBvY2N1ci4KYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gaHd5KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNyxjb2wgPSAiYmxhY2siLCBmaWxsID0gIiMxRjc3QjQiKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0iLCBzdWJ0aXRsZSA9ICJDb3VudCBvZiBIaWdod2F5IE1pbGVzIikgCmBgYAoKIyMjIyBEYXRhIG11bmdpbmcKYGBge3J9Cm10Y2FycyRjeWwgPSBhcy5mYWN0b3IobXRjYXJzJGN5bCkKbXRjYXJzCmBgYAoKCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMod3QpKSArIAogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IGZhY3RvcihjeWwpKSwgYWxwaGEgPSAwLjcpICsgeGxpbSgwLDYpKwogIGxhYnModGl0bGU9IkRlbnNpdHkgcGxvdCIsIAogICAgICAgICBzdWJ0aXRsZT0iV2VpZ2h0ICgxMDAwIGxicykgcGVyIEN5bGluZGVyIiwKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBtdGNhcnMiLAogICAgICAgICB4PSJXZWlnaHQiLAogICAgICAgICBmaWxsPSJDeWxpbmRlcnMiKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCAiIzJDQTAyQyIsIiNGRjdGMEUiKSkKCmBgYAoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyhjeWwsIHFzZWMsIGdyb3VwID0gY3lsKSkgKwogIGdlb21fYm94cGxvdCh2YXJ3aWR0aCA9IFQsIGZpbGwgPSAiIzFGNzdCNCIpICsKICBsYWJzKHRpdGxlPSJCb3hwbG90IiwgCiAgICAgICAgIHN1YnRpdGxlPSIxLzQgbWlsZSB0aW1lIHBlciBDeWxpbmRlciIsCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogbXRjYXJzIiwKICAgICAgICAgeD0iQ3lsaW5kZXJzIikKYGBgCgoKIyMjQ29tcG9zaXRpb24gCiMjIyMgQ29tcG9zaXRpb25zIGdyYXBocyBzaG93IGhvdyBhIHNpbmdsZSBlbnRpdHkgY2FuIGJlIGJyb2tlbiBkb3duIGludG8gaXRzIGNvbXBvbmVudHMgZWxlbWVudHMuIApgYGB7cn0KZ2dwbG90KGdsb2JhbCwgYWVzKHN1Yl9jYXRlZ29yeSkpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IGNhdGVnb3J5KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCB2anVzdD0wLjYpKSArCiAgIGxhYnModGl0bGU9IkNvbXBvc2l0aW9uIiwgCiAgICAgICAgIHN1YnRpdGxlPSJDb3VudHMgb2YgU3ViLUNhdGVnb3J5IC0gR3JvdXBlZCBieSBDYXRlZ29yeSIsCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogU3VwZXJzdG9yZSIsCiAgICAgICAgIHg9IlN1Yi1DYXRlZ29yeSIsCiAgICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCIjRkY3RjBFIiwgIiMyQ0EwMkMiKSkKICAKYGBgCmBgYHtyfQpnbG9iYWwKYGBgCgoKU3RhY2tlZCBDb2x1bW4KYGBge3J9CmdncGxvdChnbG9iYWwsIGFlcyhtYXJrZXQpKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBjYXRlZ29yeSkpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIHZqdXN0PTAuNikpICsKICBsYWJzKHRpdGxlPSJDYXRlZ29yeSBTdGFja2VkIC0gQmFyIENoYXJ0IiwgCiAgICAgICBzdWJ0aXRsZT0iTWFya2V0cyAtIEdyb3VwZWQgYnkgQ2F0ZWdvcnkiLCAKICAgICAgIHggPSAiTWFya2V0IiwKICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiLAogICAgICAgY2FwdGlvbj0iU291cmNlOiBTdXBlcnN0b3JlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCIjRkY3RjBFIiwgIiMyQ0EwMkMiKSkKYGBgCgoKYGBge3J9IApnbG9iYWxfdHJlZW1hcCA9IGdsb2JhbCAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDEyLCBtb250aCA9PSAnSmFuJykgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBhcy5mYWN0b3IoY291bnRyeSksCiAgICAgICAgICByZWdpb24gPSBhcy5mYWN0b3IocmVnaW9uKSwKICAgICAgICAgbWFya2V0ID0gYXMuZmFjdG9yKG1hcmtldCkpCgpsaWJyYXJ5KHRyZWVtYXBpZnkpCnRyZWVNYXBDb29yZGluYXRlcyA8LSB0cmVlbWFwaWZ5KAogIGdsb2JhbF90cmVlbWFwLAogIGFyZWEgPSAic2FsZXMiLAogIGZpbGwgPSAicHJvZml0IiwKICBncm91cCA9ICJtYXJrZXQiKQp0cmVlTWFwUGxvdCA8LSBnZ3Bsb3RpZnkodHJlZU1hcENvb3JkaW5hdGVzKQpwcmludCh0cmVlTWFwUGxvdCkKYGBgCgoKIyMjIENoYW5nZSAKIyMjI0NoYW5nZSBnaXZlcyBlbXBoYXNpcyB0byBjaGFuZ2luZyB0cmVuZHMuICAKYGBge3J9CnllYXJfMjAxMiA9IAogIGdsb2JhbCAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMjAxMikKICBnZ3Bsb3QoeWVhcl8yMDEyLCBhZXMob3JkZXJfZGF0ZSwgc2FsZXMpKSArIAogICAgZ2VvbV9saW5lKGNvbCA9ICIjMUY3N0I0IikgKyAKICAgIGZhY2V0X3dyYXAofnNlZ21lbnQsIG5yb3cgPSAzKSArCiAgICBsYWJzKHRpdGxlPSJDaGFuZ2UgVHJlbmRzIiwgCiAgICAgICBzdWJ0aXRsZT0iU2FsZXMgYnkgc2VnbWVudCIsIAogICAgICAgeCA9ICJEYXRlIiwKICAgICAgIGNhcHRpb249IlNvdXJjZTogU3VwZXJzdG9yZSIpCmBgYAoKIyMjIyBIZWF0bWFwIC0gd2l0aCBoZWF0bWFwcyB3ZSBjYW4gc3BvdCB2YXJpYXRpb25zIG9mIGEgbWV0cmljLgpgYGB7cn0KbXRjYXJzX21hdHJpeCA9ICBkYXRhLm1hdHJpeChtdGNhcnMpCmxpYnJhcnkoc3VwZXJoZWF0KQpzdXBlcmhlYXQobXRjYXJzX21hdHJpeCwKICAgICAgICAgIGxlZnQubGFiZWwuc2l6ZSA9IDAuMywKICAgICAgICAgIGxlZnQubGFiZWwudGV4dC5zaXplID0gMywKICAgICAgICAgIGxlZ2VuZC50ZXh0LnNpemUgPSAxMiwKICAgICAgICAgIHBhZGRpbmcgPSAuMSkKYGBgCgoKKioqCltWaWRlbyAtIDIzIFZpc3VhbGl6YXRpb25zIGFuZCB3aGVuIHRvIHVzZSB0aGVtXShodHRwczovL2Jsb2cuZG9taW5vZGF0YWxhYi5jb20vdmlkZW8tMjMtdmlzdWFsaXphdGlvbnMtdXNlLyk=